namespace Yaaf.Wp7.AdvancedExplorer.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.IO;
    using System.IO.IsolatedStorage;
    using System.Linq;
    using System.Threading;
    using System.Windows;
    using System.Windows.Threading;

    using Yaaf.Wp7.AdvancedExplorer.Collections.Generic;
    using Yaaf.Wp7.AdvancedExplorer.Resources;
    using Yaaf.Wp7.AdvancedExplorer.Uploading;
    using Yaaf.WP7.NativeAccess.IO;

    using Directory = Yaaf.WP7.NativeAccess.IO.Directory;
    using DirectoryInfo = Yaaf.WP7.NativeAccess.IO.DirectoryInfo;

    public class ExplorerViewModel : INotifyPropertyChanged, IPivotView
    {
        public string Header
        {
            get
            {
                return "explorer";
            }
        }

        private readonly MainViewModel mainViewModel;

        private WP7.NativeAccess.IO.DirectoryInfo currentDirectory;

        private string fullName;

        //public bool IsEnabled
        //{
        //    get
        //    {
        //        return !isListing;
        //    }
        //}

        public ExplorerViewModel(MainViewModel mainViewModel)
        {
            this.mainViewModel = mainViewModel;

            currentDirectory = new WP7.NativeAccess.IO.DirectoryInfo("");
            fullName = string.IsNullOrEmpty(currentDirectory.FullName) ? "\\" : currentDirectory.FullName;
            this.FileEntries = new ObservableCollection<FileEntryViewModel>();

            mainViewModel.PropertyChanged += new PropertyChangedEventHandler(mainViewModel_PropertyChanged);
        }

        void mainViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "CurrentFilter" && mainViewModel.CurrentView == this)
            {
                this.RefreshEntries();
            }
        }

        /// <summary>
        /// A collection for ItemViewModel objects.
        /// </summary>
        public ObservableCollection<FileEntryViewModel> FileEntries { get; private set; }
        
        public string CurrentDirectoryFullName
        {
            get
            {
                return fullName;
            }

            private set
            {
                fullName = value;
                this.NotifyPropertyChanged("CurrentDirectoryFullName");
            }
        }

        public WP7.NativeAccess.IO.DirectoryInfo CurrentDirectory
        {
            get
            {
                return currentDirectory;
            }

            set
            {
                currentDirectory = value;
                CurrentDirectoryFullName = string.IsNullOrEmpty(currentDirectory.FullName) ? "\\" : currentDirectory.FullName;

                this.RefreshEntries();
                this.NotifyPropertyChanged("CurrentDirectory");
            }
        }

        public bool IsListing
        {
            get
            {
                return isListing;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        /// <summary>
        /// Creates and adds a few ItemViewModel objects into the Items collection.
        /// </summary>
        public void LoadData()
        {
            IsolatedStorageFile f = IsolatedStorageFile.GetUserStoreForApplication();
            if (f.DirectoryExists(DeviceInfo.TempDir))
            {
                try
                {
                    Directory.Delete(PathInfo.ToGeneral(DeviceInfo.TempDir), true);
                }
                catch (UnauthorizedAccessException e)
                {
                    try
                    {
                        DeleteIsolatedDirectory(f, DeviceInfo.TempDir);
                    }
                    catch (IsolatedStorageException)
                    {
                        MessageBox.Show(string.Format(AppResources.ErrorCannotDeleteTempDir, e.Message));
                    }
                }
                catch (IOException e)
                {
                    try
                    {
                        DeleteIsolatedDirectory(f, DeviceInfo.TempDir);
                    }
                    catch (IsolatedStorageException)
                    {
                        MessageBox.Show(string.Format(AppResources.ErrorCannotDeleteTempDir, e.Message));
                    }
                }
            }

            if (App.Current != null && App.Current.RootVisual != null)
            {
                dispatcher = App.Current.RootVisual.Dispatcher;
            }

            this.RefreshEntries();
        }

        private bool isListing;

        private bool stopListing = false;
        public void RefreshEntries()
        {
            if (!FileSystemAccess.IsAvailable)
            {
                FileEntries.Clear();
                this.FileEntries.Add(new FileEntryViewModel() { ElementName = AppResources.ErrorNoFileSystemAccess });
                isListing = true;
                return;
            }

            if (isListing)
            {
                stopListing = true;
            }

            lock (workingSync)
            {
                if (this.isListing)
                {
                    throw new InvalidOperationException("Should not happen...");
                }
                this.isListing = true;
                if (App.Current != null && App.Current.RootVisual != null)
                {
                    dispatcher = App.Current.RootVisual.Dispatcher;
                }

                if (dispatcher != null)
                {
                    dispatcher.BeginInvoke(() => FileEntries.Clear());
                }
                else
                {
                    FileEntries.Clear();
                }

                stopListing = false;
                ThreadPool.QueueUserWorkItem(RefreshEntriesPrivate, dispatcher);
            }

            //this.NotifyPropertyChanged("IsEnabled");
            this.NotifyPropertyChanged("IsListing");
        }

        public string CurrentFilter
        {
            get
            {
                return this.mainViewModel.CurrentFilter;
            }
            set
            {
                this.mainViewModel.CurrentFilter = value;
            }
        }
        
        private void RefreshEntriesPrivate(object state)
        {
            try
            {
                lock (workingSync)
                {
                    try
                    {
                        foreach (var elem in this.currentDirectory.FilterEntries(this.CurrentFilter))
                        {
                            //KeyValuePair<FileEntryViewModel, bool> elem1 = elem;
                            var elem1 = new FileEntryViewModel(elem);
                            
                            mainViewModel.Invoke(()=>
                                { 
                                    this.FileEntries.Add(elem1);
                                    Extensions.SortOne(
                                        this.FileEntries,
                                        (x, y) =>
                                            {
                                                var xIsFile = x.Element is DirectoryInfo;
                                                var yIsFile = y.Element is DirectoryInfo;

                                                if (xIsFile && !yIsFile)
                                                {
                                                    return -1;
                                                }
                                                if (!xIsFile && yIsFile)
                                                {
                                                    return 1;
                                                }
                                                return x.ElementName.CompareTo(y.ElementName);
                                            });
                                });
                            
                            if (stopListing)
                            {
                                break;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Instance.WriteLine("Ignoring Exception in RefreshEntriesPrivate: {0}", e);
                    }
                    finally
                    {
                        this.isListing = false;
                    }
                }
            }
            
            finally
            {
                mainViewModel.Invoke(() =>
                {

                    // this.NotifyPropertyChanged("IsEnabled");
                    this.NotifyPropertyChanged("IsListing");
                });
            }
        }




        internal void AddTasks(FileSystemEntry entry)
        {
            var file = entry as WP7.NativeAccess.IO.FileInfo;

            

            if (file != null)
            {
                bool exists;
                try
                {
                    exists = file.Exists;
                }
                catch (UnauthorizedAccessException e)
                {
                    Logger.Instance.WriteLine("Ignoring Task due Access Restriction: " + e);
                    return;
                }

                if (exists)
                {
                    var upload = ServiceConnection.UploadTask(() => file.Open(FileMode.Open, FileAccess.Read), file.FullName);
                    this.mainViewModel.AddTasks(upload);
                }
            }

            var dir = entry as WP7.NativeAccess.IO.DirectoryInfo;
            if (dir != null)
            {
                foreach (var systemEntry in dir.Entries)
                {
                    this.AddTasks(systemEntry);
                }
            }
        }

        private readonly object workingSync = new object();
        private Dispatcher dispatcher;
        
        private void DeleteIsolatedDirectory(IsolatedStorageFile f, string tempfiles)
        {
            foreach (var directoryName in f.GetDirectoryNames(tempfiles + "\\*"))
            {
                this.DeleteIsolatedDirectory(f, tempfiles + "\\" + directoryName);
            }

            foreach (var fileName in f.GetFileNames(tempfiles + "\\*"))
            {
                f.DeleteFile(tempfiles + "\\" + fileName);
            }

            f.DeleteDirectory(tempfiles);
        }

    }
}